﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SpiderCore.Downloader;
using SpiderCore.Pipeline;
using SpiderCore;
using System.Threading;
using SpiderCore.Scheduler;
using Spider.Entitys.Spider;
using SpiderCore.Loggers;
using OpenQA.Selenium.PhantomJS;

namespace SpiderCore.Engines
{
    public class OneSpiderEngine : ISpiderEngine
    {

        #region 属性
        private readonly Thread _oneSpiderEngineThread;

        /// <summary>
        /// 下载器
        /// </summary>
        public IDownloader Downloader { get; set; }

        /// <summary>
        /// 蜘蛛模板
        /// </summary>
        public ISpider Spider { get; set; }

        /// <summary>
        /// 消息管道
        /// </summary>
        public IPipeline Pipeline { get; set; }

        /// <summary>
        /// 开启最大线程数
        /// </summary>
        private int ThreadMaxCount;

        /// <summary>
        /// 线程数组
        /// </summary>
        private Thread[] CrawlThreads;

        /// <summary>
        /// 爬虫统计
        /// </summary>
        private static int spiderCount;

        /// <summary>
        /// 页面解析规则
        /// </summary>
        private List<CustomRuleModel> CustomRuleList;

        /// <summary>
        /// 下载器工厂
        /// </summary>
        private Func<CustomRuleModel, IDownloader> _Func = null;

        /// <summary>
        /// PhantomJS 浏览器的实例 线程内唯一
        /// </summary>
        private static ThreadLocal<PhantomJSDriverModel> _phantomJsDriver = new ThreadLocal<PhantomJSDriverModel>();

        /// <summary>
        /// 爬虫模板页面解析深度
        /// </summary>
        private int depth = 0;
        #endregion

        #region 初始化

        #region 构造函数 初始化默认  下载器、爬虫、管道 各种属性
        /// <summary>
        /// 初始化爬虫模板URL规则
        /// </summary>
        /// <param name="CustomRuleList">URL解析规则列表</param>
        /// <param name="threadCount"></param>
        /// <param name="depth">页面深度</param>
        public OneSpiderEngine(List<CustomRuleModel> CustomRuleList, int threadCount = 10, int depth = 0) : this(threadCount)
        {
            this.CustomRuleList = CustomRuleList;
            this.depth = depth;

            Spider.SetSpiderDepth(depth);
            Spider.SetCustomRuleList(CustomRuleList);
        }

        /// <summary>
        /// 初始化爬虫引擎
        /// </summary>
        /// <param name="threadCount"></param>
        public OneSpiderEngine(int threadCount = 10)
        {
            #region 第一版爬虫  初始化已废弃
            //_oneSpiderEngineThread = new Thread(LoopSchedulerPop)
            //{
            //    Name = GetType().ToString()
            //};
            #endregion

            //初始化爬虫最大线程数
            this.ThreadMaxCount = threadCount;
            CrawlThreads = new Thread[threadCount];
            Downloader = new HttpDownloader();
            Spider = new Spider(CustomRuleList);
            Pipeline = new Pipelinehandler();

            #region 初始化 抓取线程
            for (int i = 0; i < ThreadMaxCount; i++)
            {
                CrawlThreads[i] = new Thread(new ParameterizedThreadStart(LoopSchedulerPop));
            }
            #endregion

        }
        #endregion

        #region 初始化日志模块
        /// <summary>
        /// 初始化日志类型
        /// </summary>
        private readonly ISpiderLogger log = new SpiderMongoDBLog(typeof(OneSpiderEngine));
        #endregion

        #region 初始化管道处理模型
        public void AddPipelineHandle(IPipelineHandler handle)
        {
            Pipeline.AddPipelineHandle(handle);
        }

        public void RemovePipelineHandle(IPipelineHandler handle)
        {
            Pipeline.RemovePipelineHandle(handle);
        }
        #endregion

        #region 初始化下载器工厂
        /// <summary>
        /// 初始化下载器工厂
        /// </summary>
        /// <param name="action"></param>
        public void InitFactoryDownloader(Func<CustomRuleModel, IDownloader> action)
        {
            _Func = action;
        }
        #endregion

        #endregion

        #region 启动线程
        /// <summary>
        /// 启动线程
        /// </summary>
        public void Start()
        {
            log.Info("启动爬虫");
            for (int i = 0; i < ThreadMaxCount; i++)
            {
                CrawlThreads[i].Start(i);
            }
            log.Info("爬虫启动完毕，启动线程数：" + CrawlThreads.Length);

            #region 第一版爬虫启动  以废弃
            //_oneSpiderEngineThread.Start(); 
            #endregion
        }
        #endregion

        #region 终止当前线程
        /// <summary>
        /// 终止当前线程
        /// </summary>
        public void Stop()
        {
            _oneSpiderEngineThread.Abort();
        }
        #endregion

        #region 继续当前线程
        /// <summary>
        /// 继续当前线程
        /// </summary>
        public void Continue()
        {
            _oneSpiderEngineThread.Resume();
        }
        #endregion

        #region 暂停当前线程
        /// <summary>
        /// 暂停当前线程
        /// </summary>
        public void Pause()
        {
            _oneSpiderEngineThread.Join();
        }
        #endregion

        /// <summary>
        /// 调度
        /// </summary>
        private void LoopSchedulerPop(object index)
        {
            while (true)
            {
                spiderCount++;
                log.Info("当前线程Id :: " + index);
                log.Info("已经抓取了 ：" + spiderCount);
                log.Info(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
                //从调度器中 弹出一条数据
                var request = SchedulerManage.Instance.Pop();
                if (request == null)
                {
                    log.Info("调度器中  已经没有可用的数据了");
                    Thread.Sleep(5000);
                    continue;
                }
                //调用下载器
                ResponseModel response = null;
                try
                {
                    response = GetDownloader(request.CustomRule, index).Download(request);
                }
                catch
                {
                    SchedulerManage.Instance.Push(request);
                }
                if (response != null)
                {
                    //爬虫提取下一级URL
                    var message = Spider.Extract(response) as HtmlMessageContext;
                    Pipeline.Push(message);
                }
                else
                {
                    log.Debug(request.Url, "下载器返回 NULL");
                    SchedulerManage.Instance.Push(request);
                }
            }
        }

        #region 私有方法

        #region 获取下载器
        /// <summary>
        /// 获取下载器
        /// </summary>
        /// <param name="rule"></param>
        /// <returns></returns>
        public IDownloader GetDownloader(CustomRuleModel rule, object threadId)
        {
            if (_Func == null)
            {
                return new HttpDownloader();
            }
            IDownloader downloader = _Func(rule);
            if (downloader.GetType() == typeof(WebDriverDownloader))
            {
                WebDriverDownloader downLoader = downloader as WebDriverDownloader;
                downLoader.SetPhantomJSDriver(GetPhantomJSDriver(threadId));
            }
            return downloader;
        }
        #endregion

        #region 获取当前线程内的 PhantomJS 浏览器的实例
        /// <summary>
        /// 获取一个 PhantomJS 浏览器的实例
        /// </summary>
        /// <returns></returns>
        private PhantomJSDriver GetPhantomJSDriver(object threadId)
        {
            if (_phantomJsDriver.Value == null)
            {
                var phantomModel = new PhantomJSDriverModel()
                {
                    CreateTime = DateTime.Now,
                    SpiderCount = 0,
                    ThreadId = threadId,
                };
                phantomModel.DriverModel = CreatePhantomJSDriver();
                _phantomJsDriver.Value = phantomModel;
            }
            if (_phantomJsDriver.Value.SpiderCount % 500 == 0)
            {
                _phantomJsDriver.Value.DriverModel.Close();
                _phantomJsDriver.Value.DriverModel.Dispose();
                _phantomJsDriver.Value.DriverModel = null;
                _phantomJsDriver.Value.DriverModel = CreatePhantomJSDriver();
            }
            return _phantomJsDriver.Value.DriverModel;
        }

        /// <summary>
        /// 创建 PhantomJS 浏览器的实例
        /// </summary>
        /// <returns></returns>
        private PhantomJSDriver CreatePhantomJSDriver()
        {
            var phantomService = GetPhantomJSDriverService();
            return new PhantomJSDriver(phantomService);
        }

        /// <summary>
        /// 获取 PhantomJSDriverService
        /// </summary>
        /// <returns></returns>
        private PhantomJSDriverService GetPhantomJSDriverService()
        {
            PhantomJSDriverService pds = PhantomJSDriverService.CreateDefaultService();
            //设置代理服务器地址
            //pds.Proxy = $"{ip}:{port}";  
            //设置代理服务器认证信息
            //pds.ProxyAuthentication = GetProxyAuthorization();
            return pds;
        }
        #endregion

        #endregion



    }
}
